using System;
using System.Text;
using System.IO;
using System.Xml;
using System.Xml.Schema;
using System.Xml.Serialization;
using System.Xml.Linq;

namespace Framework
{
    
    public static class XmlUtil<T>
    {
        #region SerializeFromFile
        /// <summary>
        /// Serializes an object from XML content in te specified file.
        /// </summary>
        /// <param name="fileName">Name of the file.</param>
        /// <returns></returns>
        public static T SerializeFromFile(string fileName)
        {
            return (T)XmlUtil.SerializeFromFile(typeof(T), fileName);
        }

        /// <summary>
        /// Serializes an object from XML content in te specified file.
        /// </summary>
        /// <param name="fileName">Name of the file.</param>
        /// <param name="postProcessor">The post processor.</param>
        /// <returns></returns>
        public static T SerializeFromFile(string fileName, Action<T> postProcessor)
        {
            var result = (T) XmlUtil.SerializeFromFile(typeof (T), fileName);

            postProcessor(result);

            return result;
        }

        /// <summary>
        /// Serializes an object from XML content in te specified file.
        /// </summary>
        /// <param name="fileName">Name of the file.</param>
        /// <param name="onException">The on exception.</param>
        /// <returns></returns>
        public static T SerializeFromFile(string fileName, OnException onException)
        {
            return (T)XmlUtil.SerializeFromFile(typeof(T), fileName, onException);
        }

        /// <summary>
        /// Serializes an object from XML content in te specified file.
        /// </summary>
        /// <param name="extraTypes">The extra types.</param>
        /// <param name="fileName">Name of the file.</param>
        /// <param name="onException">The on exception.</param>
        /// <returns></returns>
        public static T SerializeFromFile(Type[] extraTypes, string fileName, OnException onException)
        {
            return (T)XmlUtil.SerializeFromFile(typeof(T), extraTypes, fileName, onException);
        }
        #endregion
    } 

    // Common Xml Data Tasks: 
    // http://www.asp.net/QuickStart/howto/doc/Xml/OverviewofXML.aspx#
    // http://www.asp.net/QuickStart/howto/doc/Xml/XmlSchemaInference.aspx
    public static class XmlUtil
    {
        #region Notes
        /* NOTES:
         See: http://www.sys-con.com/xml/article.cfm?id=778&count=5040&tot=5&page=1
          
         If we have the XML data as a string object, we can to use the LoadXML method:
         
         const string xmlData =
         "<family location='Orlando' class='middle'>" +
         "<lastname>Solymosi</lastname>" +
         "<father>Andrew</father>" +
         "</family>";
         doc.LoadXml(xmlData);
         doc.Load(new StringReader(xmlData)); // equivalent alternative        
      */
        #endregion

        #region Escape
        /// <summary>
        /// Escapes the specified XML.
        /// </summary>
        /// <param name="xml">The XML.</param>
        /// <remarks>
        /// See: http://weblogs.sqlteam.com/mladenp/archive/2008/10/21/Different-ways-how-to-escape-an-XML-string-in-C.aspx
        /// </remarks>
        /// <returns></returns>
        public static string Escape(string xml)
        {
            return Escape(xml, true);
        }

        public static string Escape(string xml, bool encodeApostrophe)
        {
            return xml == null
                       ? string.Empty
                       : (encodeApostrophe
                              ? System.Security.SecurityElement.Escape(xml)
                              : System.Web.HttpUtility.HtmlEncode(xml));

            //var result = new StringBuilder(xml);

            //result.Replace("&", "&amp;");
            //result.Replace("<", "&lt;");
            //result.Replace(">", "&gt;");
            //result.Replace("\"", "&quot;");
            //result.Replace("\'", "&apos;");

            //return result.ToString();
        }

        #endregion

        #region EscapeLonelyAmpersand
        /// <summary>
        /// Escapes an & value that is sitting out on its own without effecting any other escaped data
        /// </summary>
        public static string EscapeLonelyAmpersand(string xml)
        {
            return StrUtil.ReplaceWhen(xml, "&", "&amp;", FrameworkConstant.DEFAULT_COMPARISON, IsLonelyAmpersand);
        }

        private static bool IsLonelyAmpersand(string searchstring, string beforeSearch, string afterSearch)
        {
            var isAmpersand = Is.EqualString(searchstring, "&");
            var isEscapeSequence = IsEscapeSeqence(afterSearch);

            return isAmpersand && !isEscapeSequence;
        }

        #endregion

        private static bool IsEscapeSeqence(string sequence)
        {
            return 
                StrUtil.StartsWith(sequence, "amp;") ||
                StrUtil.StartsWith(sequence, "lt;") ||
                StrUtil.StartsWith(sequence, "gt;") ||
                StrUtil.StartsWith(sequence, "quot;") ||
                StrUtil.StartsWith(sequence, "apos;");
        }

        public static bool HasEscapableData(string xml)
        {
            if (xml == null)
            {
                return false;
            }
            if (
                xml.IndexOf("<", StringComparison.Ordinal) > -1 ||
                xml.IndexOf("<", StringComparison.Ordinal) > -1 ||
                xml.IndexOf(">", StringComparison.Ordinal) > -1 ||
                xml.IndexOf("\"", StringComparison.Ordinal) > -1 ||
                xml.IndexOf("\'", StringComparison.Ordinal) > -1)
            {
                return true;
            }
            var ampPosition = 0;
            while (ampPosition >= 0)
            {
                ampPosition = xml.IndexOf("&", ampPosition, StringComparison.Ordinal);

                if (ampPosition >= 0)
                {
                    var textAfterAmp = StrUtil.RightOf(xml, ampPosition, 5);

                    if (IsEscapeSeqence(textAfterAmp))
                    {
                        _.P("David, Check out, this is a probelm if we have a combination of escapable and non-escapable in the same string");
                    }
                    else
                    {
                        return true;
                    }
                }
            }
            return false;
        }

        //Test &amp;lt;span class=&amp;quot;red&amp;quot;&amp;gt;Small&amp;lt;/span&amp;gt;</h3>
        // <H3><![CDATA[Test <span class="red">Small</span>]]></H3>
        // <H3>Header &amp; Footer</H3>


        #region UnEscape
        public static string UnEscape(string xml)
        {
            if (xml == null)
            {
                return string.Empty;
            }

            var result = new StringBuilder(xml);

            result.Replace("&lt;", "<");
            result.Replace("&gt;", ">");
            result.Replace("&quot;", "\"");
            result.Replace("&apos;", "\'");
            result.Replace("&amp;", "&");

            return result.ToString();
        }
        #endregion

        #region EscapeXmlBrackets
        public static string EscapeXmlBrackets(string xml)
        {
            var result = new StringBuilder(xml);

            result.Replace("<", "&lt;");
            result.Replace(">", "&gt;");

            return result.ToString();
        }
        #endregion

        #region UnEscapeXmlBrackets
        public static string UnEscapeXmlBrackets(string xml)
        {
            var result = new StringBuilder(xml);

            result.Replace("&lt;", "<");
            result.Replace("&gt;", ">");

            return result.ToString();
        }
        #endregion

        #region XmlDocumentLoad
        /// <summary>
        /// Retrieves a new XmlDocument from a file
        /// </summary>
        /// <param name="fileName">Filename to retrieve from</param>
        /// <returns>XmlDocument</returns>
        public static XmlDocument XmlDocumentLoad(string fileName)
        {
            var result = new XmlDocument();

            result.Load(fileName);

            return result;
        }
        #endregion

        #region XmlReaderToString
        /// <summary>
        /// Reads an XmlReader and returns a string
        /// </summary>
        /// <param name="XmlReader">XmlReader</param>
        /// <returns>string</returns>
        public static string XmlReaderToString(XmlReader input)
        {
            XmlDocument doc = new XmlDocument();

            doc.Load(input);

            StringWriter sw = new StringWriter();
            XmlWriter xw = new XmlTextWriter(sw);

            doc.WriteTo(xw);

            string result = sw.ToString();

            if (xw != null)
            {
                xw.Close();
            }

            return result;
        }
        #endregion

        #region XmlDocumentFromXml
        /// <summary>
        /// Retrieves a new XmlDocument from a XML string
        /// </summary>
        /// <param name="xml">Xml string to load from</param>
        /// <returns>XmlDocument</returns>
        public static XmlDocument XmlDocumentFromXml(string xml)
        {
            var result = new XmlDocument();

            result.LoadXml(xml);

            return result;
        }
        #endregion

        #region SerializeToString
        /// <summary>
        /// Serializes an object heirarchy to string
        /// </summary>
        /// <param name="o">The o.</param>
        /// <returns>String</returns>
        public static string SerializeToString(object o)
        {
            var output = new MemoryStream();
            var serializer = new XmlSerializer(o.GetType());

            serializer.Serialize(output, o);

            var result = Encoding.UTF8.GetString(output.ToArray());

            output.Close();

            return result;
        }

        /// <summary>
        /// Serializes an object heirarchy to string
        /// </summary>
        /// <param name="o">The top object in the heirarchy</param>
        /// <param name="extraTypes">Array of additional Types that can be encountered in XmlDocument</param>
        /// <returns>String</returns>
        public static string SerializeToString(object o, Type[] extraTypes)
        {
            var output = new MemoryStream();
            var serializer = new XmlSerializer(o.GetType(), extraTypes);

            serializer.Serialize(output, o);

            var result = Encoding.UTF8.GetString(output.ToArray());

            output.Close();

            return result;
        }
        #endregion

        #region SerializeToFile
        /// <summary>
        /// Serializes an object heirarchy to file
        /// </summary>
        /// <param name="o">The top object in the heirarchy</param>
        /// <param name="type">The type of the object</param>
        /// <param name="fileName">Name of the file.</param>
        public static void SerializeToFile(object o, Type type, string fileName)
        {
            SerializeToFile(o, type, null, fileName);
        }

        public static void SerializeToFile(object o, Type type, Type[] extraTypes, string fileName)
        {
            StreamWriter output = null;
            try
            {
                var serializer = extraTypes == null 
                    ? new XmlSerializer(type) 
                    : new XmlSerializer(type, extraTypes);

                output = new StreamWriter(fileName);

                serializer.Serialize(output, o);
            }
            catch (Exception ex)
            {
                LogUtil.ErrorF("XmlUtil.SerializeToFile failed to write object of type: {0}", ex, type.GetType());
                throw;
            }
            finally
            {
                if (output != null)
                {
                    output.Close();
                }
            }
        }
        #endregion

        #region SerializeToFile <T>
        public static void SerializeToFile<T>(T data, string fileName)
        {
            SerializeToFile(data, typeof(T), fileName);
        }
        #endregion

        #region SerializeFromString <T>
        /// <summary>
        /// Deserializes an object heirarchy from an XML string
        /// </summary>
        /// <param name="xml">An xml string that represents the object to create</param>
        /// <returns>Object of <var>type</var> that has been populated from XML string</returns>
        public static T SerializeFromString<T>(string xml)
        {
            return (T)SerializeFromString(typeof(T), xml, OnException.Throw);
        }

        /// <summary>
        /// Deserializes an object heirarchy from an XML string
        /// </summary>
        /// <param name="xml">An xml string that represents the object to create</param>
        /// <param name="onException">Exception should be thrown, or suppresed</param>
        /// <returns>Object of <var>type</var> that has been populated from XML string</returns>
        public static T SerializeFromString<T>(string xml, OnException onException)
        {
            return (T)SerializeFromString(typeof(T), null, xml, onException);
        }

        public static T SerializeFromString<T>(Type[] extraTypes, string xml)
        {
            return (T)SerializeFromString(typeof(T), extraTypes, xml, OnException.Throw);
        }

        /// <summary>
        /// Deserializes an object heirarchy from an XML string
        /// </summary>
        /// <param name="extraTypes"></param>
        /// <param name="xml">An xml string that represents the object to create</param>
        /// <param name="onException">Exception should be thrown, or suppresed</param>
        /// <returns>Object of <var>type</var> that has been populated from XML string</returns>
        public static T SerializeFromString<T>(Type[] extraTypes, string xml, OnException onException)
        {
            return (T)SerializeFromString(typeof(T), extraTypes, xml, onException);
        }
        #endregion

        #region SerializeFromString

        public static object SerializeFromString(string fullTypeName, string xml, OnException onException = OnException.Throw)
        {
            Type type = ReflectUtil.GetType(fullTypeName);

            return SerializeFromString(type, xml, onException);
        }

        /// <summary>
        /// Deserializes an object heirarchy from an XML string
        /// </summary>
        /// <param name="type">The type of the object to create</param>
        /// <param name="xml">An xml string that represents the object to create</param>
        /// <param name="onException">Exception should be thrown, or suppresed</param>
        /// <returns>Object of <var>type</var> that has been populated from XML string</returns>
        public static object SerializeFromString(Type type, string xml, OnException onException = OnException.Throw)
        {
            return SerializeFromString(type, null, xml, onException);
        }

        /// <summary>
        /// Deserializes an object heirarchy from an XML string
        /// </summary>
        /// <param name="type">The type of the object to create</param>
        /// <param name="extraTypes"></param>
        /// <param name="xml">An xml string that represents the object to create</param>
        /// <param name="onException">Exception should be thrown, or suppresed</param>
        /// <returns>Object of <var>type</var> that has been populated from XML string</returns>
        public static object SerializeFromString(Type type, Type[] extraTypes, string xml, OnException onException = OnException.Throw)
        {
            object result = null;
            StringReader input = null;
            try
            {
                var serializer = extraTypes == null 
                    ? new XmlSerializer(type) 
                    : new XmlSerializer(type, extraTypes);

                input = new StringReader(xml);
                result = serializer.Deserialize(input);
            }
            catch (Exception ex)
            {
                LogUtil.Error("XmlUtil.SerializeFromString: Failed to deserialize xml to object", ex);

                if (xml != null)
                {
                    LogUtil.Error(xml);
                }

                if (onException == OnException.Throw)
                {
                    throw;
                }
            }
            finally
            {
                if (input != null)
                {
                    input.Close();
                }
            }

            return result;
        }
        #endregion

        #region SerializeFromFile<T>
        /// <summary>
        /// Serializes an object from XML content in the specified file.
        /// </summary>
        /// <param name="fileName">Name of the file.</param>
        /// <returns></returns>
        public static T SerializeFromFile<T>(string fileName)
        {
            return (T)SerializeFromFile(typeof(T), fileName, OnException.Throw);
        }

        /// <summary>
        /// Serializes an object from XML content in the specified file.
        /// </summary>
        /// <param name="fileName">Name of the file.</param>
        /// <param name="onException">The on exception.</param>
        /// <returns></returns>
        public static T SerializeFromFile<T>(string fileName, OnException onException)
        {
            return (T)SerializeFromFile(typeof(T), null, fileName, onException);
        }
        public static T SerializeFromFile<T>(Type[] extraTypes, string fileName)
        {
            return (T)SerializeFromFile(typeof(T), extraTypes, fileName, OnException.Throw);
        }

        /// <summary>
        /// Serializes an object from XML content in the specified file.
        /// </summary>
        /// <param name="extraTypes">The extra types.</param>
        /// <param name="fileName">The file name to read from</param>
        /// <param name="onException">The on exception.</param>
        /// <returns>
        /// Object of <var>type</var> that has been populated from XML file
        /// </returns>
        public static T SerializeFromFile<T>(Type[] extraTypes, string fileName, OnException onException)
        {
            return (T)SerializeFromFile(typeof(T), extraTypes, fileName, onException);
        }
        #endregion

        #region SerializeFromFile

        /// <summary>
        /// Serializes an object from XML content in the specified file.
        /// </summary>
        /// <param name="fullTypeName">Full name of the type.</param>
        /// <param name="fileName">Name of the file.</param>
        /// <param name="onException">The on exception.</param>
        /// <returns></returns>
        public static object SerializeFromFile(string fullTypeName, string fileName, OnException onException = OnException.Throw)
        {
            var type = ReflectUtil.GetType(fullTypeName);

            return SerializeFromFile(type, fileName, onException);
        }
        /// <summary>
        /// Serializes an object from XML content in the specified file.
        /// </summary>
        /// <param name="type">The type.</param>
        /// <param name="fileName">Name of the file.</param>
        /// <param name="onException">The on exception.</param>
        /// <returns></returns>
        public static object SerializeFromFile(Type type, string fileName, OnException onException = OnException.Throw)
        {
            return SerializeFromFile(type, null, fileName, onException);
        }

        /// <summary>
        /// Serializes an object from XML content in the specified file.
        /// </summary>
        /// <param name="type">The type of the object to create</param>
        /// <param name="extraTypes">The extra types.</param>
        /// <param name="fileName">The file name to read from</param>
        /// <param name="onException">The on exception.</param>
        /// <returns>
        /// Object of <var>type</var> that has been populated from XML file
        /// </returns>
        public static object SerializeFromFile(Type type, Type[] extraTypes, string fileName, OnException onException = OnException.Throw)
        {
            StreamReader input = null;
            object result = null;

            try
            {
                XmlSerializer serializer = (extraTypes == null ? new XmlSerializer(type) : new XmlSerializer(type, extraTypes));
                
                input = new StreamReader(fileName);

                result = serializer.Deserialize(input);
            }
            catch (Exception)
            {
                if (type == null)
                {
                    //               //Logger.Error( "XmlSerializerUtil.SerializeFromFile, Type not supplied for file: " + fileName, ex );
                }
                else
                {
                    //               //Logger.Error( "XmlSerializerUtil.SerializeFromFile failed to read object of type: " + type.GetType( ) + " from file: " + fileName, ex );
                }

                if (onException == OnException.Throw)
                {
                    throw;
                }
            }
            finally
            {
                if (input != null)
                {
                    input.Close();
                }
            }
            return result;
        }
        #endregion

        #region SerializeFromXmlReader
        /// <summary>
        /// Deserializes an object heirarchy from a XmlReader
        /// </summary>
        /// <param name="type">The type of the object to create</param>
        /// <param name="XmlReader">Xml reader to read from</param>
        /// <returns>Object of <var>type</var> that has been populated from XmlReader</returns>
        public static object SerializeFromXmlReader(Type type, XmlReader input)
        {
            XmlSerializer serializer = null;
            object result = null;

            try
            {
                serializer = new XmlSerializer(type);

                result = serializer.Deserialize(input);
            }
            catch (Exception e)
            {
                //            //Logger.Debug( "XmlSerializerUtil.SerializeFromXmlReader failed to read object of type: " + type.GetType( ) + " from XmlReader" );
                throw e;
            }
            finally
            {
                if (input != null)
                {
                    input.Close();
                }
            }
            return result;
        }
        #endregion

        #region CloneBySerialization
        /// <summary>
        /// Clones the object by using serialization, not the fastest be will do a deep clone for objects with XML serialization attributes.
        /// </summary>
        /// <param name="o">The o.</param>
        /// <returns></returns>
        public static object CloneBySerialization(object o)
        {
            var xml = SerializeToString(o);

            return SerializeFromString(o.GetType(), xml);
        }
        #endregion

        #region GetXmlWriterSettings
        public static XmlWriterSettings GetXmlWriterSettings(bool closeOutput)
        {
            var result = new XmlWriterSettings();

            result.Indent = true;
            result.IndentChars = "   ";
            result.Encoding = Encoding.UTF8;
            result.CloseOutput = closeOutput;

            return result;
        }
        #endregion

        // XmlToXsd: http://www.15seconds.com/issue/050616.htm 
        // http://www.asp.net/QuickStart/util/srcview.aspx?path=~/howto/samples/Xml/XmlSchemaInference/XmlSchemaInference.src
        // http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dnxmlnet/html/inferschemas.asp
        #region XmlFileToXsdFile
        public static void XmlFileToXsdFile(string xmlFile, string xsdFile)
        {
            XmlWriter writer = null;
            XmlSchemaSet set = new XmlSchemaSet();
            XmlTextReader reader = new XmlTextReader(xmlFile);

            set = (new XmlSchemaInference()).InferSchema(reader);

            using (writer = XmlWriter.Create(xsdFile, GetXmlWriterSettings(true)))
            {
                foreach (XmlSchema schema in set.Schemas())
                {
                    schema.Write(writer);
                }
                writer.Flush();
            }

            reader.Close();
        }
        #endregion

        #region XmlFileToXsdString
        public static string XmlFileToXsdString(string xmlFile)
        {
            XmlWriter writer = null;
            MemoryStream output = new MemoryStream();
            XmlSchemaSet set = new XmlSchemaSet();
            XmlTextReader reader = new XmlTextReader(xmlFile);

            set = (new XmlSchemaInference()).InferSchema(reader);

            using (writer = XmlWriter.Create(output, GetXmlWriterSettings(false)))
            {
                foreach (XmlSchema schema in set.Schemas())
                {
                    schema.Write(writer);
                }
                writer.Flush();
            }

            StreamReader sw = new StreamReader(output);
            output.Position = 0;
            string result = sw.ReadToEnd();
            output.Close();
            reader.Close();

            return result;
        }
        #endregion

        #region XmlStringToXsdString
        public static string XmlStringToXsdString(string xmlContent)
        {
            XmlWriter writer = null;
            MemoryStream output = new MemoryStream();
            XmlSchemaSet set = new XmlSchemaSet();

            set = (new XmlSchemaInference()).InferSchema(new XmlTextReader(new StringReader(xmlContent)));

            using (writer = XmlWriter.Create(output, GetXmlWriterSettings(false)))
            {
                foreach (XmlSchema schema in set.Schemas())
                {
                    schema.Write(writer);
                }
                writer.Flush();
            }

            StreamReader sw = new StreamReader(output);
            output.Position = 0;
            string result = sw.ReadToEnd();
            output.Close();

            return result;
        }
        #endregion

        #region XmlStringToXsdFile
        public static void XmlStringToXsdFile(string xmlContent, string xsdFile)
        {
            XmlWriter writer = null;
            XmlSchemaSet set = new XmlSchemaSet();

            set = (new XmlSchemaInference()).InferSchema(new XmlTextReader(new StringReader(xmlContent)));

            using (writer = XmlWriter.Create(xsdFile, GetXmlWriterSettings(true)))
            {
                foreach (XmlSchema schema in set.Schemas())
                {
                    schema.Write(writer);
                }
                writer.Flush();
            }
        }
        #endregion

        #region GetNodeValue
        // from Microsoft Crm 
        // http://msdn.microsoft.com/library/en-us/dnmbscrm1_2/html/mbs_crmcstmintpostcallouts1d21.asp
        // at the end of note 14.
        public static string GetNodeValue(string input, string searchName)
        {
            if (input == null || searchName == null)
            {
                return String.Empty;
            }

            int rootStart = input.IndexOf('<' + searchName + '>');
            if (rootStart == -1)
            {
                // Could be a node with attributes
                rootStart = input.IndexOf('<' + searchName + ' ');
                if (rootStart == -1)
                {
                    return String.Empty;
                }
            }
            int startIndex = input.IndexOf(">", rootStart) + 1;
            int endIndex = input.IndexOf("</" + searchName + '>',
                startIndex);
            if (endIndex == -1)
            {
                // Empty node
                return String.Empty;
            }
            string rVal = input.Substring(startIndex, endIndex - startIndex);
            // XML also encodes ' to &apos;, which HTML does not.
            // Normalize it here.
            return rVal.Replace("&apos;", "'");
        }
        #endregion

        #region ToXml
        public static string ToXml(object o)
        {
            string result = null;

            MemoryStream output = new MemoryStream();
            XmlSerializer serializer = new XmlSerializer(o.GetType());

            serializer.Serialize(output, o);

            result = Encoding.UTF8.GetString(output.ToArray());

            output.Close();

            return result;
        }
        #endregion

        #region ToXmlDocument
        public static XmlDocument ToXmlDocument(object data)
        {
            var result = new XmlDocument();

            var xmlData = (data is string ? (string)data : SerializeToString(data));

            result.LoadXml(xmlData);

            return result;
        }
        #endregion

        #region ToXElement
        public static XElement ToXElement(object o)
        {
            string result = null;

            MemoryStream output = new MemoryStream();
            XmlSerializer serializer = new XmlSerializer(o.GetType());

            serializer.Serialize(output, o);

            result = Encoding.UTF8.GetString(output.ToArray());

            output.Close();

            return XElement.Parse(result);
        }
        #endregion

        #region GetAttributeValue
        /// <summary>
        /// Gets the attribute value. Returns a String.Empty if not found.
        /// </summary>
        /// <param name="element">The element.</param>
        /// <param name="attributeName">Name of the attribute.</param>
        /// <returns></returns>
        public static string GetAttributeValue(XElement element, string attributeName)
        {
            return GetAttributeValue(element, attributeName, String.Empty);
        }
        /// <summary>
        /// Gets the attribute value. Returns a default value if not found.
        /// </summary>
        /// <param name="element">The element.</param>
        /// <param name="attributeName">Name of the attribute.</param>
        /// <param name="defaultValue">The default value to use if attribute is not found.</param>
        /// <returns></returns>
        public static string GetAttributeValue(XElement element, string attributeName, string defaultValue)
        {
            var result = element.Attribute(attributeName);

            return (result == null ? defaultValue : result.Value);
        }
        #endregion

        #region GetElementValue (System.Xml.LINQ.XElement)
        /// <summary>
        /// Gets the element value. Returns a String.Empty if not found.
        /// </summary>
        /// <param name="element">The element.</param>
        /// <param name="elementName">Name of the element.</param>
        /// <returns></returns>
        public static string GetElementValue(XElement element, string elementName)
        {
            return GetElementValue(element, elementName, String.Empty);
        }
        /// <summary>
        /// Gets the element value. Returns a default value if not found.
        /// </summary>
        /// <param name="element">The element.</param>
        /// <param name="elementName">Name of the Element.</param>
        /// <param name="defaultValue">The default value to use if Element is not found.</param>
        /// <returns></returns>
        public static string GetElementValue(XElement element, string elementName, string defaultValue)
        {
            var result = element.Element(elementName);

            return (result == null ? defaultValue : result.Value);
        }
        #endregion

        #region GetElementAttributeValue (System.Xml.LINQ.XElement)
        /// <summary>
        /// Gets the element value with the matching Name attribute.
        /// </summary>
        /// <param name="element">The element.</param>
        /// <param name="elementName">Name of the Element.</param>
        /// <param name="attributeName">The name attribute to match on.</param>
        /// <returns></returns>
        public static string GetElementAttributeValue(XElement element, string elementName, string attributeName)
        {

            foreach (var oElement in element.Elements(elementName))
            {
                return GetAttributeValue(oElement, attributeName);
            }

            return string.Empty;
        }
        #endregion

        #region GetElementValue (System.Xml.XmlElement)
        /// <summary>
        /// Gets the element value. Returns a String.Empty if not found.
        /// </summary>
        /// <param name="element">The element.</param>
        /// <param name="elementName">Name of the element.</param>
        /// <returns></returns>
        public static string GetElementValue(XmlElement element, string elementName)
        {
            return GetElementValue(element, elementName, String.Empty);
        }
        /// <summary>
        /// Gets the element value. Returns a default value if not found.
        /// </summary>
        /// <param name="element">The element.</param>
        /// <param name="elementName">Name of the Element.</param>
        /// <param name="defaultValue">The default value to use if Element is not found.</param>
        /// <returns></returns>
        public static string GetElementValue(XmlElement element, string elementName, string defaultValue)
        {
            XmlElement result = element[elementName];

            return (result == null ? defaultValue : result.Value);
        }
        #endregion

        #region SetElementValue (System.Xml.LINQ.XElement)
        /// <summary>
        /// Sets the element value.
        /// </summary>
        /// <param name="element">The element.</param>
        /// <param name="elementName">Name of the Element.</param>
        /// <param name="value">The value.</param>
        /// <returns></returns>
        public static void SetElementValue(XElement element, string elementName, string value)
        {
            var result = element.Element(elementName);

            if (result == null)
            {
                element.Add(new XElement(elementName, value));
            }
            else
            {
                result.Value = value;
            }
        }
        #endregion

        #region SetElementAttributeValue (System.Xml.LINQ.XElement)
        public static void SetElementAttributeValue(XElement element, string elementName, string attributeName, string value)
        {
            var targetElement = element.Element(elementName);

            if (targetElement == null)
            {
                return;
            }

            targetElement.SetAttributeValue(attributeName, value);
        }
        #endregion

        // *********************************************************************************
        // Cleanup XML strings
        // *********************************************************************************

        #region StripTempUri
        public static string StripTempUri(string xml)
        {
            xml = xml.Replace(" xmlns=\"http://tempuri.org/\"", String.Empty);

            return xml;
        }
        #endregion

        #region StripXml
        public static string StripXml(string xml)
        {
            return 
                StripXmlHeader(
                    StripXmlSchema(xml)); //StripRssSchema(xml)
        }

        public static string StripXmlHeader(string xml)
        {
            xml = xml.Replace("<?xml version=\"1.0\"?>\r\n", String.Empty);
            xml = xml.Replace("<?xml version=\"1.0\"?>", String.Empty);

            return xml;
        }
        public static string StripXmlSchema(string xml)
        {
            xml = xml.Replace(" xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\"", String.Empty);
            xml = xml.Replace(" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"", String.Empty);

            return xml;
        }
        public static string StripXmlNamespace(string xml, string namespaceValue)
        {
            var search1 = string.Format(" xmlns=\"{0}\"", namespaceValue);
            var search2 = string.Format(" xmlns='{0}'", namespaceValue);

            xml = xml.Replace(search1, String.Empty);
            xml = xml.Replace(search2, String.Empty);

            return xml;
        }

        // Don't usethis, use the Namespace attribute instead
        //public static string StripRssSchema(string xml)
        //{
        //    xml = xml.Replace(" xmlns:atom=\"http://www.w3.org/2005/Atom\"", String.Empty);

        //    return xml;
        //}
        #endregion

        // *********************************************************************************
        // Soap Envelop
        // *********************************************************************************

        #region SoapEnvelopWrap
        /// <summary>
        /// Wraps and XML string with a SOAP envelop.
        /// </summary>
        /// <param name="xml">The XML.</param>
        /// <returns></returns>
        public static string SoapEnvelopWrap(string xml)
        {
            return SoapEnvelopWrap(true, xml);
        }

        /// <summary>
        /// Wraps and XML string with a SOAP envelop.
        /// </summary>
        /// <param name="isCrLf">if set to <c>true</c> [is cr lf].</param>
        /// <param name="xml">The XML.</param>
        /// <returns></returns>
        public static string SoapEnvelopWrap(bool isCrLf, string xml)
        {
            var result = new TextStringBuilder();

            SoapEnvelopWrite(result, isCrLf, "<?xml version=\"1.0\" encoding=\"utf-8\"?>");
            SoapEnvelopWrite(result, isCrLf, "<env:Envelope xmlns:env=\"http://schemas.xmlsoap.org/soap/envelope/\">");
            SoapEnvelopWrite(result, isCrLf, "<env:Body xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\">");
            SoapEnvelopWrite(result, isCrLf, xml);
            SoapEnvelopWrite(result, isCrLf, "</env:Body>");
            SoapEnvelopWrite(result, isCrLf, "</env:Envelope>");

            //SoapEnvelopWrite(result, isCrLf, "<?xml version=\"1.0\" encoding=\"UTF-8\"?>");
            //SoapEnvelopWrite(result, isCrLf, "<env:Envelope xmlns:env=\"http://schemas.xmlsoap.org/soap/envelope/\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\" env:encodingStyle=\"http://schemas.xmlsoap.org/soap/encoding/\">");
            //SoapEnvelopWrite(result, isCrLf, "<env:Body xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\">");
            //SoapEnvelopWrite(result, isCrLf, "<env:Header />");
            //SoapEnvelopWrite(result, isCrLf, "<env:Body>");

            //SoapEnvelopWrite(result, isCrLf, xml);
            //SoapEnvelopWrite(result, isCrLf, "</env:Body>");
            //SoapEnvelopWrite(result, isCrLf, "</env:Envelope>");

            return result.ToString();
        }

        private static void SoapEnvelopWrite(TextWriter result, bool isCrLf, string text)
        {
            if (isCrLf)
            {
                result.WriteLine(text);
            }
            else
            {
                result.Write(text);
            }
        }
        #endregion
    }
}
